import { defineStore } from "pinia";
import type { AccountLoginParams, LoginAccountInfo } from "@/api";
import {
  accountLogin,
  accountLogout,
  refreshAccountToken,
  getLoginAccountInfo,
} from "@/api";
import { useState } from "@/hooks";
import { computed } from "vue";
import { setRefreshTokenFn, setRefreshAuthFn, setGetTokenFn } from "@/config";
import { generateRouteMetaRawTree, flatRouteMetaResolveRaw } from "@/utils";
import { routes } from "@/router";
import type { RouteMeta } from "vue-router";

export { LoginAccountInfo };

/** 用户信息初始化 */
export const getUserInfoInit = (): LoginAccountInfo => {
  return {
    id: 0,
    name: "",
    mobile: "",
    avatar: "",
    token: "",
    refresh_token: "",
    permission: [],
    role_id: 0,
    role_name: "",
  };
};

export const useUserStore = defineStore("USER", () => {
  /** 用户钩子 */
  const userInfoHook = useState<LoginAccountInfo>(getUserInfoInit(), {
    moduleKey: "USER_STORE",
    debug: false,
    cache: true,
  });

  /**
   * 基本状态
   */
  const userInfo = computed(() => userInfoHook.state);

  /** token */
  const token = computed(() => userInfo.value.token);

  /** 是否登录 */
  const isLogin = computed(() => !!token.value);

  /** refreshToken */
  const refreshToken = computed(() => userInfo.value.refresh_token);

  /** 权限列表 */
  const permissionList = computed(() => userInfo.value.permission || []);

  /** 有权限的路由树 */
  const havePermissionRouteTree = computed(() =>
    generateRouteMetaRawTree(routes, {
      // 配置权限且有权限 或 (未配置权限无子路由(即末端子路由) 或 子路由有权限)
      filterFn: (raw, haveChildren, haveChildrenRaw) =>
        raw.checkPermission
          ? permissionList.value.includes(raw.permissionKey!)
          : !haveChildrenRaw || haveChildren,
      sortFn: (a, b) => a.menuSort - b.menuSort,
    }),
  );

  /** 扁平化有权限的路由 */
  const flatHavePermissionRouteList = computed(() =>
    flatRouteMetaResolveRaw(havePermissionRouteTree.value),
  );

  /** 有权限的路由路径列表 */
  const havePermissionPathList = computed(() => {
    return flatHavePermissionRouteList.value.map((item) => item.path);
  });

  /** 无api退出登录[接口告知未登录 同步内存状态] */
  const noApiLogout = () => {
    userInfoHook.resetState();
  };

  const logout = async () => {
    try {
      if (isLogin.value) {
        await accountLogout();
      }
    } catch (error) {
      console.error("退出登录失败", error);
    }
    noApiLogout();
  };

  const login = async (params: AccountLoginParams) => {
    // 静默退出登录
    noApiLogout();
    const { data } = await accountLogin(params);
    userInfoHook.updateState(data);
  };

  const getInfo = async () => {
    const { data } = await getLoginAccountInfo();
    userInfoHook.updateState({
      ...data,
      refresh_token: refreshToken.value,
      token: token.value,
    });
    return data;
  };

  const refreshTokenFn = async () => {
    const { data } = await refreshAccountToken({
      Authorization: refreshToken.value,
    });
    userInfoHook.updateState({
      ...userInfo.value,
      token: data.token,
    });
  };

  setGetTokenFn(() => token.value);

  setRefreshTokenFn(refreshTokenFn);

  setRefreshAuthFn(getInfo);

  /**
   * 通过路由地址判断是否有权限
   * !!!此处假定子页面被授权，父页面也被授权，与权限配置时相关，权限配置时只配置最末端子页面
   */
  const havePermissionByPath = (path: string) => {
    return havePermissionPathList.value.includes(path);
  };

  /** 通过权限key判断是否有权限 */
  const havePermissionByKey = (
    key?: Required<RouteMeta>["permission"]["key"],
  ) => {
    return permissionList.value.includes(key!);
  };

  watch(
    isLogin,
    (n, o) => {
      n && (o ?? getInfo());
    },
    {
      immediate: true,
    },
  );

  watch(token, (n, o) => {
    // 令牌变化时重新获取用户信息
    n && o && getInfo();
  });

  return {
    userInfo,
    token,
    isLogin,
    login,
    logout,
    noApiLogout,
    getInfo,
    havePermissionByPath,
    havePermissionByKey,
  };
});
